package com.javacasino.casino.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.javacasino.casino.config.ThreadTaskAsync;
import com.javacasino.casino.entity.BeginGame;
import com.javacasino.casino.entity.OnLoadInfo;
import com.javacasino.casino.entity.OnLogiResponse;
import com.javacasino.casino.entity.login.LoginInfo;
import com.javacasino.casino.entity.login.Master;
import com.javacasino.casino.entity.login.Slave;
import com.javacasino.casino.service.WebSocketService;
import com.javacasino.casino.util.MapStaticConstants;
import com.javacasino.casino.util.StaticsConstants;
import com.javacasino.casino.util.ThreadPool;
import com.javacasino.casino.util.ThreadTask;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.enums.ReadyState;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.net.URI;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;


@Slf4j
@Service
public class WebSocketServiceimpl implements WebSocketService {

    @Autowired
    private RedisService redisService;

    private ThreadPool threadPool = new ThreadPool();


    @Autowired
    private ThreadTaskAsync async;


    /**
     *
     */
    public final String sid_one = "e67dbf5bcdd1b592f360d4d799609c40fc37001e";
    public final String sid_two = "4e166245e1a4e975a3cc1a9d2406120bc6ae5a0b";
    public final String sid_3 = "e45c8ddb17396415c54e580905a9272e108fb6e1";

    /**
     * 获取单号及其他信息
     * @param sid
     * @return
     */
    @Override
    public String loadOrderNum(String sid) {
        OnLogiResponse onLogiResponse =  redisService.getCacheObject(sid);
        if(onLogiResponse!=null){
            try{
                List<BeginGame> beginGames = redisService.getCacheList(StaticsConstants.ORDERNUM+onLogiResponse.getHallID().toString());
                Optional<BeginGame> gameOP = beginGames.stream().max(Comparator.comparing(BeginGame::getWagersID)).filter(Objects::nonNull);
                //下单标识
                boolean flag = redisService.getCacheObject(StaticsConstants.BET+sid);
                //目标单号
                String targetOrder = redisService.getCacheObject(StaticsConstants.ONBEGINGAME_TARGET_ORDERNUM);
                if(!CollectionUtils.isEmpty(beginGames)&&gameOP.get() != null
                    && flag
                && StringUtils.isNotEmpty(targetOrder)
                && gameOP.isPresent()){
//                    for (BeginGame beginGame : beginGames) {
                        //计算差值
                        Long difference = Long.parseLong(targetOrder)-Long.parseLong(gameOP.get().getWagersID());
                        Master master = redisService.getCacheObject(StaticsConstants.MASTER_SID_INFO +sid);
                        Long interval_one = Long.parseLong(targetOrder)-Long.parseLong(master.getInterval_one());
                        Long Interval_two = Long.parseLong(targetOrder)-Long.parseLong(master.getInterval_two());
                        Double value = 0.0;
                        //获取余额
                        String balance = redisService.getCacheObject(StaticsConstants.MASTER_BALANCE+master.getMainNumber());
                        if((Double.valueOf(gameOP.get().getCredit()/10))>Double.valueOf(balance)){
                            value = (Double.valueOf(gameOP.get().getCredit()/10))-Double.valueOf(balance);
                        }else {
                            value = Double.valueOf(balance)-(Double.valueOf(gameOP.get().getCredit()/10));
                        }
                        JSONObject json = new JSONObject();
                        json.put("difference",String.valueOf(difference));
                        json.put("interval_one_load",String.valueOf(interval_one));
                        json.put("Interval_two_load",String.valueOf(Interval_two));
                        json.put("balance",String.valueOf(balance));
                        json.put("value",String.valueOf(value));
////                    if(beginGame.getWagersID().equals(targetOrder) && flag){
////                        beginGames.add("已中奖");
////                    }else if(!flag){
////                        beginGames.add("停止下单");
////                    }else{
////                        return "0";
////                    }
//                    }

                return JSONObject.toJSONString(json);
                }else{
                    if(!flag){
                        return "停止下单";
                    }else{
                        return "0";
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
                return "0";
            }
        }else{
            return "0";
        }
    }

    @Override
    public Boolean login(LoginInfo message) {
        try {
            if (!CollectionUtils.isEmpty(message.getSlaveList())) {
                for (Slave slave : message.getSlaveList()) {
                    CustomizedWebSocketClient customizedWebSocketClient = new CustomizedWebSocketClient(new URI("wss://dianzizone.com/fxCasino/fxLB?gameType=5902"), new Draft_6455());
                    customizedWebSocketClient.connect();
                    //检测是否断线，断线后断线重连
                    while (!ReadyState.OPEN.equals(customizedWebSocketClient.getReadyState())) {
                    }
                    //存储 监控号对象信息
                    redisService.setCacheObject(StaticsConstants.SLAVE_SID_INFO + slave.getMonitor(), slave);

                    customizedWebSocketClient.send(getLongInfo(slave.getMonitor()));
                    Thread.sleep(2000);
                    JSONObject json2 = new JSONObject();
                    json2.put("action", "onLoadInfo2");
                    customizedWebSocketClient.send(String.valueOf(json2));
                    Thread.sleep(2000);
                    //拿到登录账号
                    OnLogiResponse response = redisService.getCacheObject(slave.getMonitor());
                    //账号信息
                    OnLoadInfo loadInfo = redisService.getCacheObject(response.getHallID().toString());
                    //存储监控号信息
                    redisService.setCacheObject(StaticsConstants.SLAVE+response.getHallID().toString(),loadInfo);
                    //判断账户内的余额是否充足
//                    if(Double.parseDouble(loadInfo.getBalance()) <= Double.parseDouble(slave.getExchange())){
//                        log.info("账户余额不足：{}",loadInfo.getBalance());
//                        return false;
//                    }
//                    if(Double.valueOf(loadInfo.getCredit()) < (Double.valueOf(slave.getExchange())*10)
//                        && Double.parseDouble(loadInfo.getBalance()) >= Double.parseDouble(slave.getExchange())){
                        //兑换点数
                        JSONObject json3 = new JSONObject();
                        json3.put("action", "creditExchange");
                        json3.put("rate", "1:10");
                        BigDecimal a = new BigDecimal(slave.getExchange()).multiply(new BigDecimal(10)).setScale(0, BigDecimal.ROUND_DOWN);
                        json3.put("credit", a.toString());
                        customizedWebSocketClient.send(String.valueOf(json3));
//                    }

                    //存储兑换的金额
                    redisService.setCacheObject(StaticsConstants.SLAVE_EXCHANGE+slave.getMonitor(),slave.getExchange());
                    //存储监控号余额
                    redisService.setCacheObject(StaticsConstants.SLAVE_BALANCE+slave.getMonitor(),loadInfo.getBalance());
                    //存储socke 链接对象
                    MapStaticConstants.clients.put(slave.getMonitor(), customizedWebSocketClient);

                    //存储 目标单号
                    redisService.setCacheObject(StaticsConstants.TARGET_ORDER, slave.getTargetOrder());
                    //默认可以单
                    redisService.setCacheObject(StaticsConstants.BET + slave.getMonitor(),true);
                }

            } else if (!CollectionUtils.isEmpty(message.getMasterList())) {
                //登录主号
                for (Master master : message.getMasterList()) {
                    CustomizedWebSocketClient webSocketClient = new CustomizedWebSocketClient(new URI("wss://dianzizone.com/fxCasino/fxLB?gameType=5902"), new Draft_6455());
                    webSocketClient.connect();
                    //检测是否断线，断线后断线重连
                    while (!ReadyState.OPEN.equals(webSocketClient.getReadyState())) {
                    }
                    webSocketClient.send(getLongInfo(master.getMainNumber()));
                    Thread.sleep(2000);
                    JSONObject json2 = new JSONObject();
                    json2.put("action", "onLoadInfo2");
                    webSocketClient.send(String.valueOf(json2));
                    //拿到登录账号
                    OnLogiResponse response = redisService.getCacheObject(master.getMainNumber());
                    //账号信息
                    OnLoadInfo loadInfo = redisService.getCacheObject(response.getHallID().toString());
                    //存储余额
                    redisService.setCacheObject(StaticsConstants.MASTER_BALANCE+master.getMainNumber(),loadInfo.getBalance());

                    //止盈目标
                    String take = String.valueOf(new BigDecimal(loadInfo.getBalance()).setScale(1,BigDecimal.ROUND_DOWN)
                            .add(new BigDecimal(master.getTake()).setScale(1,BigDecimal.ROUND_DOWN)));
                    redisService.setCacheObject(StaticsConstants.TARGET_PROFIT + master.getMainNumber(),take);
                    //兑换点数
                    JSONObject json3 = new JSONObject();
                    json3.put("action", "creditExchange");
                    json3.put("rate", "1:10");
                    BigDecimal a = new BigDecimal(loadInfo.getBalance()).multiply(new BigDecimal(10)).setScale(0, BigDecimal.ROUND_DOWN);
                    json3.put("credit", a.toString());
                    webSocketClient.send(String.valueOf(json3));
                    //存储socke 链接对象
                    MapStaticConstants.clients.put(master.getMainNumber(), webSocketClient);
                    //存储 主号对象信息
                    redisService.setCacheObject(StaticsConstants.MASTER_SID_INFO + master.getMainNumber(), master);
                    //默认还未下单
                    redisService.setCacheObject(StaticsConstants.BET+master.getMainNumber(),false);
                }
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * @param sid
     * @param sleep 延迟多久下一单 单位  毫秒
     * @return
     * @throws Exception
     */
    @Override
    public String slavePlaceOrder(String sid, int sleep,boolean is_bet) throws Exception {
        CustomizedWebSocketClient customizedWebSocketClient = MapStaticConstants.clients.get(sid);
        //测试循环时间
        for (int i = 0; i < 15; i++) {
            threadPool.placeOrder(new ThreadTask(sid, getLongInfo(sid), convert(sid), 1, getLine(1, 10), customizedWebSocketClient));
        }
        if(!is_bet){
//            int i = 0;
//            Slave slave = redisService.getCacheObject(StaticsConstants.SLAVE_SID_INFO+sid);
//            redisService.setCacheObject(StaticsConstants.BET+sid,true);
//            while (redisService.getCacheObject(StaticsConstants.BET + sid)) {
//                CustomizedWebSocketClient client = MapStaticConstants.clients.get(sid);
//                //如果断线了，重新登录 并且兑换点数
//                if (reconnection(sid,client)) {
//                    client.send(convert(sid));
//                }
//                //休眠
//                Thread.sleep(sleep);
//                String balance = redisService.getCacheObject(StaticsConstants.SLAVE_BALANCE+slave.getMonitor());
//                int result = new BigDecimal(balance).setScale(1,BigDecimal.ROUND_DOWN).compareTo(new BigDecimal(slave.getMoney()).setScale(1,BigDecimal.ROUND_DOWN));
//                //判断监控号余额
//                if(result < 0){
//                    return "监控号余额不足";
//                }
//                //下单
////                client.send(getLine(Integer.valueOf(slave.getNote()),
////                        Integer.valueOf(String.valueOf(new BigDecimal(slave.getMoney()).multiply(new BigDecimal(10)).setScale(0, BigDecimal.ROUND_DOWN)))));
//                client.send(getLine(1,Integer.valueOf(slave.getMoney())*10));
//                balance = String.valueOf(new BigDecimal(balance).subtract(new BigDecimal(slave.getMoney())).setScale(1,BigDecimal.ROUND_DOWN));
//                redisService.setCacheObject(StaticsConstants.SLAVE_BALANCE+slave.getMonitor(),balance);
//                log.info("监控号下单----{}", i);
//            }
            return "停止下单";
        }else{
            redisService.setCacheObject(StaticsConstants.BET+sid,is_bet);
            log.info("监控号停止下单----{}", sid);
            return "停止下单";
        }

    }

    /**
     * 断线重连
     *
     * @param sid
     * @param client
     * @throws Exception
     */
    public boolean reconnection(String sid, CustomizedWebSocketClient client) throws Exception {
        boolean flag = false;
        if (client.isClosed()) {
            client.connect();
            while (!ReadyState.OPEN.equals(client.getReadyState())) {
            }
            client.send(getLongInfo(sid));
            Thread.sleep(2000);
            JSONObject json2 = new JSONObject();
            json2.put("action", "onLoadInfo2");
            client.send(String.valueOf(json2));
            flag = true;
        }
        return flag;
    }


    /**
     * 主号开始被监控下单
     */
    @Override
    public void bet(String sid, Boolean b) {
        //line 多少注
        //lineBet 每注多少点数  10点等于1块钱
//        {"action": "beginGame2","line": "1","lineBet": "10"}
//        CustomizedWebSocketClient client = MapStaticConstants.clients.get(sid);
//        if (client.isClosed()) {
//            client.connect();
//            client.send(getLongInfo(sid));
//        }
//        while (!ReadyState.OPEN.equals(client.getReadyState())) {
//        }
        redisService.setCacheObject(StaticsConstants.BET + sid, b);
        log.info("主号开始被监控下单---------{}", sid);
    }

    /**
     * 登录信息
     *
     * @param sid
     * @return
     */
    public String getLongInfo(String sid) {
        JSONObject dInfo = new JSONObject();
        dInfo.put("rd","fx");
        dInfo.put("ua","Mozilla/5.0 (Windows NT 10.0; WOW64)  AppleWebKit/537.36 (KHTML, like  Gecko)Chrome/86.0.4240.198 Safari/537.36");
        dInfo.put("os","Windows 10");
        dInfo.put("srs","1920x1080");
        dInfo.put("wrs","1024x767");
        dInfo.put("dpr","1");
        dInfo.put("pl","H5");
        dInfo.put("pf","Chrome86.0.4240.198");
        dInfo.put("wv","false");
        dInfo.put("aio","false");
        dInfo.put("vga","ANGLE (Intel(R) HD Graphics 630 Direct3D11 vs_5_0 ps_5_0)");
        dInfo.put("tablet","false");
        dInfo.put("cts","1624375920340");
        dInfo.put("mua","");
        dInfo.put("dtp","");

        JSONObject json = new JSONObject();
        json.put("action", "loginBySid");
        json.put("sid", sid);
        json.put("gtype", "5902");
//        json.put("dInfo", dInfo);
        return json.toString();
    }

    /**
     * 下单json
     *
     * @param line    下多少注
     * @param lineBet 每注多少点数？ 10点等于1块钱
     * @return
     */
    public String getLine(int line, int lineBet) {
        JSONObject json = new JSONObject();
        json.put("action", "beginGame2");
        json.put("line", line);
        json.put("lineBet", lineBet);
        return json.toJSONString();
    }

    /**
     * 兑换点数
     *
     * @param sid
     * @return
     */
    public String convert(String sid) {
        //拿到登录账号
        OnLogiResponse response = redisService.getCacheObject(sid);
        //账号信息
        OnLoadInfo loadInfo = redisService.getCacheObject(response.getHallID().toString());
        //兑换点数
        JSONObject json3 = new JSONObject();
        json3.put("action", "creditExchange");
        json3.put("rate", "1:10");
        BigDecimal a = new BigDecimal(loadInfo.getBalance()).multiply(new BigDecimal(10)).setScale(0, BigDecimal.ROUND_DOWN);
        json3.put("credit", a.toString());
        return json3.toString();
    }

    /**
     * 内部类
     */
    public class CustomizedWebSocketClient extends WebSocketClient {


        /**
         * 线程安全的Boolean -是否受到消息
         */
        public AtomicBoolean hasMessage = new AtomicBoolean(false);

        /**
         * 线程安全的Boolean -是否已经连接
         */
        private AtomicBoolean hasConnection = new AtomicBoolean(false);

        public CustomizedWebSocketClient(URI serverUri, Draft_6455 draft_6455) {
            super(serverUri);
        }

        /**
         * 打开链接
         *
         * @param serverHandshake
         */
        @Override
        public void onOpen(ServerHandshake serverHandshake) {
            log.info("打开链接");
        }

        /**
         * 收到消息
         *
         * @param s
         */
        @Override
        public void onMessage(String s) {
            log.info("获取信息={}", s);
            if (s.contains("onLogin")) {
                Map mapTypes = JSON.parseObject(s);
                Map result = JSON.parseObject(mapTypes.get("result").toString());
                if ((boolean) result.get("event")) {
                    OnLogiResponse data = JSONObject.parseObject(result.get("data").toString(), OnLogiResponse.class);
                    redisService.setCacheObject(data.getSid(), data);
                    log.info("获取登录信息={}", data);
                }
            } else if (s.contains("onOnLoadInfo2")) {
                //获取登录账号信息
                Map mapTypes = JSON.parseObject(s);
                Map result = JSON.parseObject(mapTypes.get("result").toString());
                if ((boolean) result.get("event")) {
                    try {
                        OnLoadInfo data = JSONObject.parseObject(result.get("data").toString(), OnLoadInfo.class);

//                        Slave slave = redisService.getCacheObject(StaticsConstants.SLAVE_SID_INFO+data.getSid());
//                        if(slave!=null){
//                            redisService.setCacheObject(StaticsConstants.SLAVE+data.getHallID(), data);
//                        }else{
                            redisService.setCacheObject(data.getHallID(), data);
//                        }
                        log.info("获取登录账号信息={}", data);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            } else if (s.contains("onBeginGame")) {
                //获取订单号
                Map mapTypes = JSON.parseObject(s);
                Map result = JSON.parseObject(mapTypes.get("result").toString());
                if ((boolean) result.get("event")) {
                    BeginGame data = JSONObject.parseObject(result.get("data").toString(), BeginGame.class);
                    redisService.setCachePutList(StaticsConstants.ORDERNUM +data.getBBJackpot().getPools().get(1).getPoolID(), data);
                    redisService.expire(StaticsConstants.ORDERNUM +data.getBBJackpot().getPools().get(1).getPoolID(),86400);
                    log.info("获取订单号信息={}", data);

                    //保存各个主账号阈值单号
                    //获取目标单号
                    //目标单号单独存储在redis中
//                    594217957259
//                    594217944001
                    String targetOrder = redisService.getCacheObject(StaticsConstants.TARGET_ORDER);
                    String tagetOrder = data.getWagersID().substring(0,data.getWagersID().length() - targetOrder.length());//目标单号
                    StringBuffer sb = new StringBuffer();
                    sb.append(tagetOrder);
                    sb.append(targetOrder);
                    String tagetOrderStr = new String(sb);
                    //存储拼接好的目标单号
                    redisService.setCacheObject(StaticsConstants.ONBEGINGAME_TARGET_ORDERNUM,tagetOrderStr);

                    //获取所有主号
                    Collection<String> collections = redisService.keys(StaticsConstants.MASTER_SID_INFO+"*");

                    if (!CollectionUtils.isEmpty(collections)) {
                        //最好改为多线程模式计算通知
                        for (String collection : collections) {
                            Master master = redisService.getCacheObject(collection);
                            if(StringUtils.isNotEmpty(master.getInterval_one())&&StringUtils.isNotEmpty(master.getInterval_two())){

                                Long intervalOne = Long.parseLong(tagetOrderStr) - Long.parseLong(master.getInterval_one());
                                Long intervalTwo = Long.parseLong(tagetOrderStr) - Long.parseLong(master.getInterval_two());
                                String sid = master.getMainNumber();

                                //判断重连
                                CustomizedWebSocketClient  client = MapStaticConstants.clients.get(sid);
                                boolean flag = false;
                                if (client.isClosed()) {
                                    client.connect();
                                    client.send(getLongInfo(sid));
                                    flag = true;
                                }
                                while (!ReadyState.OPEN.equals(client.getReadyState())) {
                                }
                                //兑换点数
                                if (flag) {
                                    client.send(convert(sid));
                                }

                                //每个主号下单开关
                                boolean masterFlag = redisService.getCacheObject(StaticsConstants.BET + master.getMainNumber());
                                OnLoadInfo onLoadInfo = redisService.getCacheObject(StaticsConstants.SLAVE+data.getBBJackpot().getPools().get(1).getPoolID());
                                if(onLoadInfo==null){
                                    if (Long.parseLong(data.getWagersID()) >= intervalOne
                                            && Long.parseLong(data.getWagersID()) <= intervalTwo
                                            && masterFlag
                                    ) {
                                        // TODO: 通知主号下单
                                        OnLoadInfo masteronLoadInfo = redisService.getCacheObject(data.getBBJackpot().getPools().get(1).getPoolID());
                                        if(masteronLoadInfo!=null){
                                            int balanceFlag = new BigDecimal(masteronLoadInfo.getBalance()).setScale(1,BigDecimal.ROUND_DOWN)
                                                    .compareTo(new BigDecimal(master.getMoney()).setScale(1,BigDecimal.ROUND_DOWN));
                                            if(balanceFlag >= 0){
                                                for (int i = 0; i < 15; i++) {
//                                                    threadPool.placeOrder(new ThreadTask(sid, getLongInfo(sid), convert(sid), 1, getLine(Integer.parseInt(master.getNote()), Integer.parseInt(master.getMoney())), client));
                                                }
                                            }else{
                                                //余额不足停止下单
                                                redisService.setCacheObject(StaticsConstants.BET + master.getMainNumber(), false);
                                            }
                                        }
                                    } else if (tagetOrderStr.equals(data.getWagersID())) {
                                        //中奖后停止主号下单
                                        redisService.setCacheObject(StaticsConstants.BET + master.getMainNumber(), false);
                                    }
                                }
                            }
                        }
                    }
//                redisService.getCacheObject("sid_info:"+slave.getMonitor(),slave);
                }

//        }else if (s.contains("onTakeMachine")){
//        }else if (s.contains("updateMarquee")){
            }
            hasMessage.set(true);
        }

//    public Class<?> jsonToEntity(String s, Class<?> clazz){
//        Map mapTypes = JSON.parseObject(s);
//        Map result = JSON.parseObject(mapTypes.get("result").toString());
//        if((boolean)result.get("event")){
//            clazz = (Class<?>) JSONObject.parseObject(result.get("data").toString(), clazz);
//            log.info("获取信息={}",clazz);
//        }
//        return clazz;
//    }


        /**
         * 关闭链接
         *
         * @param i
         * @param s
         * @param b
         */
        @Override
        public void onClose(int i, String s, boolean b) {
            super.close();
            log.info("关闭链接={}", s);
            this.hasMessage.set(false);
            this.hasConnection.set(false);
        }

        /**
         * 发生错误
         *
         * @param e
         */
        @Override
        public void onError(Exception e) {

        }

        @Override
        public void connect() {
            if (!this.hasConnection.get()) {
                super.connect();
                hasConnection.set(true);
            }
        }

    }
}
